﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Windows.Forms;
using Argos.Data.Model;
using Argos.Diagnostics;
using System.Configuration;
using System.Text;
using ArgosDesktop.Diagnostics;

namespace ArgosDesktop
{
	static class Program
	{

		private static object TargetLock = new object();
		private static string[] SourceNames = new string[] { "Argos", "ArgosDesktop" };


		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main()
		{

			if (UserSettings.Default.EnableLogging)
			{
				Program.EnableTracing();
			}

			Application.ThreadException += Program.Application_ThreadException;

			Tracer.TraceData(TraceEventType.Verbose, 0, "Application Starting...");

			EnsureDataStorageFolder();

			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new Main());

			Tracer.TraceData(TraceEventType.Verbose, 0, "Application Exited.");
		}

		internal static void DeleteTarget(Target target)
		{
			if (null == target)
			{
				throw new ArgumentNullException("target");
			}

			lock (TargetLock)
			{
				string path = GetTargetStorageFile(target.Id).FullName;
				if (File.Exists(path))
				{
					File.Delete(path);
				}

				path = string.Format(@"{0}\{1}.teststate", UserSettings.Default.TargetStorageFolder, target.Id);
				if (File.Exists(path))
				{
					File.Delete(path);
				}
			}
		}

		internal static void DisableTracing()
		{
			foreach (string name in SourceNames)
			{
				TraceSource source = Tracer.GetTraceSource(name);
				source.Switch.Level = SourceLevels.Off;
			}
		}

		internal static void EnableTracing()
		{
			EnsureLogStorageFolder();

			if (UserSettings.Default.EnableLogging)
			{
				foreach (string name in SourceNames)
				{
					TraceSource source = Tracer.GetTraceSource(name);
					source.Switch.Level = UserSettings.Default.LoggingLevel;

					DesktopTraceListener listener = source.Listeners["ArgosDesktopLogger"] as DesktopTraceListener;
					if (null != listener)
					{
						source.Listeners.Remove(listener.Name);
					}

					listener = new DesktopTraceListener(UserSettings.Default.LogFolderPath);
					listener.TraceOutputOptions = TraceOptions.DateTime | TraceOptions.ThreadId;
					listener.Name = "ArgosDesktopLogger";
					listener.Filter = new EventTypeFilter(UserSettings.Default.LoggingLevel);
					source.Listeners.Add(listener);
				}

			}
		}

		internal static void EnsureAlertStorageFolder()
		{
			if (!Directory.Exists(UserSettings.Default.AlertStorageFolder))
			{
				Directory.CreateDirectory(UserSettings.Default.AlertStorageFolder);
			}
		}

		internal static void EnsureDataStorageFolder()
		{
			if (!Directory.Exists(UserSettings.Default.DataStorageFolder))
			{
				Assembly asm = Assembly.GetExecutingAssembly();
				string folder = string.Format(
					@"{0}\{1}\{2}\{3}",
					Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
					asm.GetCompanyName(),
					asm.GetProductName(),
					asm.GetAssemblyVersion()
				);

				Directory.CreateDirectory(folder);
				UserSettings.Default.DataStorageFolder = folder;
				UserSettings.Default.Save();
			}

		}

		internal static void EnsureLogStorageFolder()
		{
			if (!Directory.Exists(UserSettings.Default.LogFolderPath) && !string.IsNullOrEmpty(UserSettings.Default.LogFolderPath))
			{
				Directory.CreateDirectory(UserSettings.Default.LogFolderPath);
			}
		}

		internal static void EnsurePersistenceStorageFolder()
		{
			if (!Directory.Exists(UserSettings.Default.PersistenceStorageFolder))
			{
				Directory.CreateDirectory(UserSettings.Default.PersistenceStorageFolder);
			}
		}

		internal static void EnsureTargetsStorageFolder()
		{
			if (!Directory.Exists(UserSettings.Default.TargetStorageFolder))
			{
				Directory.CreateDirectory(UserSettings.Default.TargetStorageFolder);
			}
		}

		internal static object GetTestState(Guid targetId)
		{
			string path = string.Format(@"{0}\{1}.teststate", UserSettings.Default.TargetStorageFolder, targetId);
			if (File.Exists(path))
			{
				lock (TargetLock)
				{
					using (FileStream strm = new FileStream(path, FileMode.Open, FileAccess.Read))
					{
						if (strm.Length > 0)
						{
							BinaryFormatter bf = new BinaryFormatter();
							try
							{
								return bf.Deserialize(strm);
							}
							catch { }
						}
					}
				}
			}
			return null;
		}

		internal static Target OpenTarget(Guid targetId)
		{
			FileInfo fi = GetTargetStorageFile(targetId);

			if (File.Exists(fi.FullName))
			{
				lock (TargetLock)
				{
					return Target.ReadXml(fi);
				}
			}

			return null;
		}

		internal static List<Target> OpenTargets()
		{
			List<Target> list = new List<Target>();

			EnsureTargetsStorageFolder();

			string[] files = Directory.GetFiles(UserSettings.Default.TargetStorageFolder);

			foreach (string file in files)
			{
				try
				{
					Target t = null;
					lock (TargetLock)
					{
						t = Target.ReadXml(new FileInfo(file));
					}
					list.Add(t);
				}
				catch { }
			}

			return list;
		}

		internal static void SaveTarget(Target target)
		{
			if (null == target)
			{
				throw new ArgumentNullException("target");
			}

			FileInfo fi = GetTargetStorageFile(target.Id);
			lock (TargetLock)
			{
				target.WriteXml(fi);
			}
		}

		internal static void SaveTestState(Guid targetId, object state)
		{
			EnsureTargetsStorageFolder();
			string path = string.Format(@"{0}\{1}.teststate", UserSettings.Default.TargetStorageFolder, targetId);

			if (null != state)
			{
				lock (TargetLock)
				{
					using (FileStream strm = new FileStream(path, FileMode.Create, FileAccess.Write))
					{
						BinaryFormatter bf = new BinaryFormatter();
						bf.Serialize(strm, state);
					}
				}
			}
			else if(File.Exists(path))
			{
				try
				{
					lock (TargetLock)
					{
						File.Delete(path);
					}
				}
				catch { }
			}
		}

		internal static void ShowException(Form parentForm, string message, Exception ex)
		{
			MessageBox.Show(parentForm, string.Format("{0}\n\n{1}", message, ex), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}



		private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
		{
			Tracer.TraceData(TraceEventType.Critical, 0, "An unhandled exception was encountered in 'ArgosDesktop'.", e.Exception);
		}

		private static FileInfo GetTargetStorageFile(Guid targetId)
		{
			EnsureTargetsStorageFolder();
			string filePath = string.Format(@"{0}\{1}.xml", UserSettings.Default.TargetStorageFolder, targetId);
			return new FileInfo(filePath);
		}

	}
}
